package com.coder4j.starter.generator.service;

import com.alibaba.fastjson.JSON;
import com.coder4j.starter.generator.GeneratorItemsEnum;
import com.coder4j.starter.generator.mapper.GeneratorMapper;
import com.coder4j.starter.generator.vo.*;
import com.coder4j.starter.mybatis.BaseEntityEnums;
import com.coder4j.starter.tools.util.DateUtils;
import com.coder4j.starter.tools.util.FileUtils;
import com.coder4j.starter.tools.util.Mysql2JavaTypeCaster;
import com.coder4j.starter.tools.util.StringUtils;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.FileResourceLoader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.*;

/**
 * 核心逻辑
 *
 * @author Keller
 * @date 2020-11-13 17:48:16
 */
@Service
public class WebGeneratorService {

    /**
     * 文件分隔符，用于匹配不同文件系统（主要是Windows和MacOS、Linux）的差异
     */
    public static String separator = File.separator;
    @Value("${generator.templatePath}")
    String templatePath;
    @Value("${generator.tempCodePath}")
    public String tempCodePath;
    /**
     * mapper，用于执行数据库操作，获取表结构信息
     */
    @Resource
    private GeneratorMapper mapper;


    private List<TableColumnVO> getColumnList(String tableName) {
        //从数据库中查询出基本的列信息
        List<ColumnInfo> columnList = mapper.baseQueryColumnList(tableName);
        IndexInfo indexInfo = new IndexInfo();
        indexInfo.setTableName(tableName);
        //查询出索引列
        List<IndexInfo> indexList = mapper.baseQueryIndexList(indexInfo);

        Map<String, String> indexMap = new HashMap<>();
        if (indexList != null && indexList.size() > 0) {
            for (IndexInfo index : indexList) {
                indexMap.put(index.getColumnName(), index.getKeyName());
            }
        }

        //构建模版中可用的列信息
        List<TableColumnVO> list = new ArrayList<>();

        for (ColumnInfo item : columnList) {
            TableColumnVO vo = new TableColumnVO();
            if (indexMap.containsKey(item.getColumnName())) {
                vo.setIndex(true);
            } else {
                vo.setIndex(false);
            }
            //数据库字段名，用于Mapper中的查询语句
            vo.setName(item.getColumnName());
            //数据库中的数据类型
            vo.setType(item.getColumnType());
            //注释
            vo.setComment(item.getColumnComment());
            if ("PRI".equalsIgnoreCase(item.getColumnKey())) {
                vo.setKey(true);
            }


            //Java字段名
            vo.setJavaName(StringUtils.lineToHump(vo.getName()));
            //getter方法名
            vo.setGetterName(StringUtils.lineToBigHump(vo.getName()));
            //Java的数据类型
            vo.setJavaType(Mysql2JavaTypeCaster.getJavaType(vo.getType()));
            //ts的数据类型
            vo.setTsType(Mysql2JavaTypeCaster.getTsType(vo.getType()));
            //是否必填
            vo.setRequired("NO".equals(item.getIsNullable()));

            vo.setIsTableColumn(true);
            vo.setColumnTitle(vo.getComment());


            //默认基础字段不填写
            vo.setIsFormData(!BaseEntityEnums.isBaseColumn(vo.getName()));
            //默认必填字段或索引字段必填
            vo.setFormNotNull(vo.getRequired() || vo.isIndex());

            list.add(vo);
        }
        return list;
    }

    /**
     * 根据表结构和配置信息，初始化模板
     *
     * @return
     */
    public TemplateVO initTemplate(String tableName) {

        List<TableColumnVO> list = this.getColumnList(tableName);

        TemplateVO template = new TemplateVO();
        //设置字段列表
        template.setList(list);

        String instanceName = StringUtils.lineToHump(tableName);

        String entityName = StringUtils.firstToUpper(instanceName);

        String tempPath = "tempCode_" + DateUtils.getShortTimeMask();

        template.setTemplatePath(templatePath);
        template.setUserTempPath(tempPath);
        template.setJavaPath(tempPath + File.separator + "java");
        template.setVuePath(tempPath + File.separator + "web");
        template.setSqlPath(tempPath + File.separator + "sql");
        template.setEntityName(entityName);
        template.setInstanceName(instanceName);
        template.setTableName(tableName);
        template.setTableComment(this.getTableComment(tableName));
        template.setMenuName(template.getTableComment());
        template.setAuthor("keller");
        // TODO
//        template.setPackageName(params.getPackageName());

        int indexCount = 0;
        //设置数据表解析信息
        for (TableColumnVO item : list) {
            if (item.isKey()) {
                //设置主键
                template.setKeyField(item);
            }
            if (item.isIndex() && !item.getJavaName().equals("id")) {
                indexCount++;
            }
        }

        int querySpan = 0;
        if (indexCount <= 1) {
            querySpan = 24;
        } else if (indexCount <= 2) {
            querySpan = 12;
        } else if (indexCount <= 3) {
            querySpan = 8;
        } else if (indexCount == 6) {
            querySpan = 8;
        } else {
            querySpan = 6;
        }

        template.setQuerySpan(querySpan);

        return template;
    }

    /**
     * 生成临时代码
     * @param vo
     */
    public CodeContentVO generatorTempCode(TemplateVO template) {
        //TODO 检查请求参数

        CodeContentVO vo = new CodeContentVO();
        String fileName = "";
        String content = "";
        String path = "";
        String entityName = template.getEntityName();
        String instanceName = template.getInstanceName();
        if(template.getGeneratorItems().contains(GeneratorItemsEnum.java.name())){
            vo.setJavaFiles(vo.initJavaFiles());
            for (CodeContentVO.FileVO file : vo.getJavaFiles()) {
                file.setFileName(entityName + file.getFileName());
                if(StringUtils.notEmpty(template.getJavaTestPath())){
                    String filePath  = file.getFilePath().replace("java","");
                    filePath = template.getJavaTestPath() + filePath;
                    file.setFilePath(filePath);
                }
                file.setContent(this.doCreate(template,file.getFileName(),file.getTemplateFile(),file.getFilePath()));
                vo.getLogs().add(new CodeContentVO.RunLog(file.getFileName(),DateUtils.getDateTime()));
            }
        }
        if(template.getGeneratorItems().contains(GeneratorItemsEnum.vue.name())){
            vo.setVueFiles(vo.initVueFiles());
            for (CodeContentVO.FileVO file : vo.getVueFiles()) {
                if(file.getFileName().equals("Api.ts")){
                    file.setFileName(entityName+file.getFileName());
                }else {
                    file.setFilePath(file.getFilePath() + instanceName);
                    file.setProjectPath(file.getProjectPath() + instanceName);
                }

                if(StringUtils.notEmpty(template.getVueTestPath())){
                    String filePath  = file.getFilePath().replace("vue","");
                    filePath = template.getVueTestPath() + filePath;
                    file.setFilePath(filePath);
                }
                file.setContent(this.doCreate(template,file.getFileName(),file.getTemplateFile(),file.getFilePath()));
                vo.getLogs().add(new CodeContentVO.RunLog(file.getFileName(),DateUtils.getDateTime()));
            }
        }
        if(template.getGeneratorItems().contains(GeneratorItemsEnum.menu.name())){
            vo.setSqlFiles(vo.initSqlFiles());
            for (CodeContentVO.FileVO file : vo.getSqlFiles()) {
                file.setFileName(template.getEntityName()+file.getFileName());
                if(StringUtils.notEmpty(template.getSqlTestPath())){
                    file.setFilePath(template.getSqlTestPath());
                }
                file.setContent(this.doCreate(template,file.getFileName(),file.getTemplateFile(),file.getFilePath()));
                vo.getLogs().add(new CodeContentVO.RunLog(file.getFileName(),DateUtils.getDateTime()));
            }
       }
        return vo;
    }


    /**
     * 执行创建方法
     *
     * @param template     模板对象
     * @param templateName 模板文件名
     */
    private String doCreate(TemplateVO template, String fileName, String templateName,String path) {
        String basePath = tempCodePath;
        if(StringUtils.notEmpty(template.getTempCodePath())){
            basePath = template.getTempCodePath();
        }
        String filePath = basePath + File.separator + template.getUserTempPath() + File.separator + path  ;

        if(StringUtils.isEmpty(template.getUserTempPath())){
            filePath = basePath + File.separator + path  ;
        }
        template.setTemplateName(templateName);
        return createFile(template, filePath, fileName);
    }

    private String createFile(TemplateVO template, String filePath, String fileName) {
        try {
            //指定模板路径
            String root = template.getTemplatePath() + File.separator;

            FileResourceLoader resourceLoader = new FileResourceLoader(root, "utf-8");

            Configuration cfg = Configuration.defaultConfiguration();
            GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
            //指定要加载的模板
            Template t = gt.getTemplate(template.getTemplateName());
            //绑定全局变量
            t.binding("template", template);
            //读取模板输出的文本
            String str = t.render();
            System.out.println(str);
            File dir = new File(filePath + File.separator);
            if (!dir.exists() && !dir.isDirectory()) {
                dir.mkdirs();
            }
            File file = new File(dir + File.separator + fileName);
            if (!file.exists()) {
                file.createNewFile();
            }
            FileWriter fileWriter = new FileWriter(file);
            BufferedWriter bw = new BufferedWriter(fileWriter);
            bw.write(str);
            bw.flush();
            bw.close();

            List<String> list = FileUtils.readFromFile(dir + File.separator + fileName);
            String fileContent = String.join("\n",list);
            return fileContent;
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return "";
    }

    private String getTableComment(String tableName) {
        List<String> list = mapper.baseQueryTableComment(tableName);
        if (list == null || list.isEmpty()) {
            return "";
        }
        return list.get(0);
    }


}
